#include "World.h"
#include <fstream>
#include <sstream>
using namespace std;


int pause_push = 0, space_push = 0;
int frame_count = 0;
int World::lvl_max = 3;
//-------------------------------------------------------
const int World::map_w = 30;
//-------------------------------------------------------
const int World::map_h = 20;
//-------------------------------------------------------
string World::intToString(int num){
    std::ostringstream ss;
    ss << num;
    return ss.str();
}
//-------------------------------------------------------
World::World(RenderWindow* wnd){
    lvl = 1;
    lvl_up = false;
    loose = false;
    pause = false;
    menu = false;
    go = false;
    preview = true;
    discharge = false;

    eng = new Engine(wnd);
    robot = new DinamicAnimation("img/robot", 4);//!!!! num_frames
    indicator = new Indicator("img/indicator");
    girl = new StaticAnimation("img/girlfriend", 5);//!!!! num_frames

    map = new int*[map_h];
    for(int i = 0; i < map_h; i++)
        map[i] = new int[map_w];

    init(intToString(lvl));
}
//-------------------------------------------------------
// 0 - floor
// 1 - wall
// 2 - wire
// 3 - enemy
// 4 - robot
// 5 - girl
void World::init(string level){
    wires.clear();
    indicator->charge();
    string str = "maps/" + level + ".txt";
    const char * path = str.c_str();
    ifstream file_map(path, ofstream::in);
    char id;

    discharge = false;

    for(int i = 0; i < map_h; i++)//y coord
        for(int j = 0; j < map_w; j++){//x coord
            if (file_map >> id){
                map[i][j] = id - 48;
                switch( map[i][j] ){
                    case 2:{//wire
                            StaticAnimation wire("img/wire", 3);//!!!! num_frames
                            wire.setPosition(j*30, i*29);//background frame 29x30
                            wires.push_back(wire);
                            map[i][j] = 0;
                            break;
                           }
                    case 4:{//robot
                            robot->setPosition(j*30, i*29);//background frame 29x30
                            indicator->setPosition(robot->getX() - 5, robot->getY() - 10);
                            map[i][j] = 0;
                            break;
                           }
                    case 5:{//girl
                            girl->setPosition(j*30, i*29);//background frame 29x30
                            girl->setName("img/girlfriend");
                            map[i][j] = 0;
                            break;
                           }
                    case 6:{//hole
                            girl->setPosition(j*30, i*29);//background frame 29x30
                            girl->setName("img/hole");
                            map[i][j] = 0;
                            break;
                           }
                }
            }
        }
}
//-------------------------------------------------------
void World::collision(int dig_x, int dig_y){
    for(int i = robot->getX()/30; i < (robot->getX()+69)/30; i++)//background frame 29x30, robot frame 69x70
        for(int j = robot->getY()/29; (j < (robot->getY()+70)/29) && (j < map_h); j++){//background frame 29x30, robot frame 69x70
            if( map[j][i] == 1){
                if( dig_x > 0 ) robot->setPosition(i*30-69, robot->getY());//background frame 29x30, robot frame 69x70
                if( dig_x < 0 ) robot->setPosition((i+1)*30, robot->getY());//background frame 29x30
                if( dig_y > 0 ) robot->setPosition(robot->getX(), j*29-70);//background frame 29x30, robot frame 69x70
                if( dig_y < 0 ) robot->setPosition(robot->getX(), (j+1)*29);//background frame 29x30
            }
        }
}
//-------------------------------------------------------
void World::checkWires(){
    int coordX = robot->getX()+ 35;//robot frame 69x70 (69/2=35)
    int coordY = robot->getY() + 40;//robot frame 69x70
    for(int i = 0; i < wires.size(); i++)
        if( (coordX >= wires[i].getX()) && (coordX <= wires[i].getX()+49) )//wire frame 49x50
            if( (coordY >= wires[i].getY()) && (coordY <= wires[i].getY()+49) )//wire frame 49x50
                indicator->charge();
}
//-------------------------------------------------------
bool World::isGirlFound(){
    char dir = robot->getDirection();
    int coordX = robot->getX();
    int coordY = robot->getY();

    if( dir == 'u'){
        if( (coordX >= girl->getX()) && (coordX <= girl->getX()+69) )//girl frame 69x70
            if( (coordY >= girl->getY()) && (coordY <= girl->getY()+70) )//girl frame 69x70
                return true;
        if( (coordX + 69 >= girl->getX()) && (coordX + 69 <= girl->getX()+69) )//girl frame 69x70
            if( (coordY >= girl->getY()) && (coordY <= girl->getY()+70) )//girl frame 69x70
                return true;
    }

    if( dir == 'l'){
        if( (coordX >= girl->getX()) && (coordX <= girl->getX() + 69) )//girl frame 69x70
            if( (coordY >= girl->getY()) && (coordY <= girl->getY()+70) )//girl frame 69x70
                return true;
        if( (coordX >= girl->getX()) && (coordX  <= girl->getX()+69) )//girl frame 69x70
            if( (coordY +70 >= girl->getY()) && (coordY + 70 <= girl->getY()+70) )//girl frame 69x70
                return true;
    }

    if( dir == 'd'){
        if( (coordX >= girl->getX()) && (coordX <= girl->getX()+69) )//girl frame 69x70
            if( (coordY + 70 >= girl->getY()) && (coordY + 70 <= girl->getY()+70) )//girl frame 69x70
                return true;

        if( (coordX + 69 >= girl->getX()) && (coordX + 69 <= girl->getX()+69) )//girl frame 69x70
            if( (coordY + 70 >= girl->getY()) && (coordY + 70 <= girl->getY()+70) )//girl frame 69x70
                return true;
    }

    if( dir == 'r'){
        if( (coordX + 69 >= girl->getX()) && (coordX + 69 <= girl->getX()+69) )//girl frame 69x70
            if( (coordY >= girl->getY()) && (coordY <= girl->getY()+70) )//girl frame 69x70
                return true;

        if( (coordX + 69 >= girl->getX()) && (coordX + 69 <= girl->getX()+69) )//girl frame 69x70
            if( (coordY + 70 >= girl->getY()) && (coordY + 70 <= girl->getY()+70) )//girl frame 69x70
                return true;
    }

    return false;
}
//-------------------------------------------------------
void World::checkInput(float time){
    if(eng->isKeyPressed('u')){
        robot->setDirection('u');
        robot->moveY(-1, time);
        collision(0, -1);
        robot->animate(time);
        if(!discharge) discharge = true;
    }
    if(eng->isKeyPressed('d')){
        robot->setDirection('d');
        robot->moveY(1, time);
        collision(0, 1);
        robot->animate(time);
        if(!discharge) discharge = true;
    }
    if(eng->isKeyPressed('l')){
        robot->setDirection('l');
        robot->moveX(-1, time);
        collision(-1, 0);
        robot->animate(time);
        if(!discharge) discharge = true;
    }
    if(eng->isKeyPressed('r')){
        robot->setDirection('r');
        robot->moveX(1, time);
        collision(1, 0);
        robot->animate(time);
        if(!discharge) discharge = true;
    }
    checkPause();
}
//-------------------------------------------------------
void World::checkPause(){
    if(eng->isKeyPressed('e')){
        pause_push = 1;
    }
    else
        if(pause_push == 1){
            if(pause)
                pause = false;
            else
                pause = true;
            pause_push = 0;
        }

    if (pause)
        go = false;
    else
        go = true;
}
//-------------------------------------------------------
void World::play(float time){
    checkInput(time);
    checkWires();

    girl->animate(time);
    indicator->setPosition(robot->getX() - 5, robot->getY() - 10);
    if(discharge) indicator->animate(time);
    for(int i = 0; i < wires.size(); i++)
        wires[i].animate(time);

    if(isGirlFound()){
        lvl ++;
        lvl_up = true;
    }
    render();
}
//-------------------------------------------------------
void World::clearWindow(){
    eng->clearWindow();
    eng->drawSprite("img/menu/paper_crumpled.png",0,0);
}
//-------------------------------------------------------
bool World::nextFramePreview(){
    if(eng->isKeyPressed('s')){
        space_push = 1;
        return false;
    }
    else
        if(space_push == 1){
            space_push = 0;
            return true;
        }
        else
            return false;
}
//-------------------------------------------------------
void World::scenario(float time){
    clearWindow();

    if(preview){
        int prev_frames = 10;
        clearWindow();
        eng->drawSprite("img/preview/part" + intToString(frame_count) + ".png", 0, 0);
        eng->renderWindow();

        if (nextFramePreview()) frame_count++;

        if( frame_count == prev_frames){
            go = true;
            preview = false;
        }
    }
    else{
        if( lvl > lvl_max ){
            if(eng->isMouseClickInRect(338, 424, 180, 39)){ // main_menu rect
                menu = true;
                lvl = 1;
                go = false;
                lvl_up = false;
            }
            eng->drawSprite("img/menu/happy_end.png",0,0);
            eng->renderWindow();
        }
        else{//if the game not finished
            if(loose){
                if(eng->isMouseClickInRect(111, 425, 263, 47)){ // restart rect
                    init(intToString(lvl));
                    loose = false;
                }

                if(eng->isMouseClickInRect(492, 427, 167, 31)){ // main_menu rect
                    menu = true;
                    loose = false;
                    go = false;
                }
                eng->drawSprite("img/menu/bad_end.png",0,0);
                eng->renderWindow();
            }
            else{//if you not loose
                if (lvl_up){
                    eng->drawSprite("img/menu/next_level.png",0,0);
                    eng->renderWindow();
                    Clock delay;
                    while( delay.getElapsedTime().asSeconds() < 2.0){}
                    init(intToString(lvl));
                    lvl_up = false;
                }

                if(indicator->isDischarge()){
                    loose = true;
                    indicator->charge();
                }

                if(pause){
                    checkPause();

                    if(eng->isMouseClickInRect(222, 241, 322, 45)){ // continue rect
                        pause = false;
                        go = true;
                    }

                    if(eng->isMouseClickInRect(269, 317, 267, 54)){ // restart rect
                        init(intToString(lvl));
                        pause = false;
                        go = true;
                    }

                    if(eng->isMouseClickInRect(318, 389, 183, 35)){ // main_menu rect
                        menu = true;
                        pause = false;
                        Clock delay;
                        while( delay.getElapsedTime().asMilliseconds() < 250){}
                    }

                    if(eng->isMouseClickInRect(344, 460, 116, 36)){ // exit rect
                        eng->closeWindow();
                    }
                    eng->drawSprite("img/menu/pause.png",0,0);
                    eng->renderWindow();
                }
                if (menu){
                    if(eng->isMouseClickInRect(287, 245, 221, 95)){ // play rect
                        lvl = 1;
                        init(intToString(lvl));
                        go = true;
                        menu = false;
                    }

                    if(eng->isMouseClickInRect(330, 388, 147, 42)) // exit rect
                        eng->closeWindow();

                    eng->drawSprite("img/menu/main_menu.png",0,0);
                    eng->renderWindow();
                }
                if(go)
                    play(time);
            }
        }
    }
}
//-------------------------------------------------------
void World::render(){
    for(int i = 0; i < map_h; i++)
        for(int j = 0; j < map_w; j++){
            if(map[i][j] == 1)
                    if( ( i+1 < map_h) && ( map[i+1][j] == 0 ) )
                        eng->drawSprite("img/shadow_wall.png", j*30, i*29);//background frame 29x30
                    else
                        eng->drawSprite("img/wall.png", j*30, i*29);//background frame 29x30
        }

    for(int i = 0; i < wires.size(); i++)
        eng->drawSprite(wires[i].getFramePath(), wires[i].getX(), wires[i].getY());

    eng->drawSprite(girl->getFramePath(), girl->getX(), girl->getY());
    eng->drawSprite(indicator->getCurrentFrame(), indicator->getX(), indicator->getY());
    eng->drawSprite(robot->getFramePath(), robot->getX(), robot->getY());
    eng->renderWindow();
}
//-------------------------------------------------------
bool World::isWindowOpen(){
    return eng->isWindowOpen();
}
